﻿namespace Sai.Core.Sandcastle
{
	using System.Collections.Generic;
	using System.IO;
	using System.Text;
	using System.Xml;
	using Sai.Core.Reporting;

	/// <summary>
	/// Hierarchical map of topic ids (found in topic tag of .aml file) to title.
	/// </summary>
	public class ContentLayout
	{
		public ContentLayout()
		{
			this.Topics = new TopicCollection();
		}

		public ContentLayout(Project project)
			: this()
		{
			this.Project = project;
		}

		private TopicCollection Topics { get; set; }

		private Project Project { get; set; }

		public void Add(Topic topic)
		{
			this.Topics.Add(topic);
		}

		// save
		public void SaveTo(TextWriter writer)
		{
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;
			settings.CloseOutput = true;
			settings.Encoding = Encoding.UTF8;
			settings.OmitXmlDeclaration = true;

			using (var xml = XmlWriter.Create(writer, settings))
			{
				xml.WriteStartDocument();
				xml.WriteStartElement("Topics");

				foreach (Topic topic in this.Topics)
				{
					topic.WriteXml(xml);
				}

				xml.WriteEndElement();
				xml.WriteEndDocument();
			}
		}

		public static ContentLayout LoadFrom(TextReader reader)
		{
			return ContentLayout.LoadFrom(reader, null);
		}

		public static ContentLayout LoadFrom(TextReader reader, Project p)
		{
			XmlDocument document = new XmlDocument();
			document.Load(reader);

			List<ReportIndex> indices = new List<ReportIndex>();

			if (p != null)
			{
				// now find all content in the project
				foreach (string projectItem in p.Content)
				{
					if (File.Exists(projectItem))
					{
						using (var topicFileReader = new StreamReader(projectItem))
						{
							Identifier id = TopicIdReader.LoadFrom(topicFileReader);

							indices.Add(new ReportIndex() { Guid = id.Value, Path = projectItem });
						}
					}
				}
			}

			ContentLayout layout = new ContentLayout(p);

			foreach (XmlNode topLevelNode in document.ChildNodes)
			{
				foreach (XmlNode topic in topLevelNode.ChildNodes)
				{
					var entry = new Topic();
					entry.LoadNode(topic);

					ReportIndex i = indices.Find(x => entry.Matches(x.Guid));

					if (i != null)
					{
						entry.Path = i.Path;
					}

					layout.Add(entry);
				}
			}

			return layout;
		}

		public void FindAndReplace(string guid, Topic newContent)
		{
			Topic replace = this.Topics.SearchByGuid(guid);

			if (replace != null && newContent.Matches(guid))
			{
				if (this.Project != null)
				{
					ReportIndexCollectionBuilder builder = new ReportIndexCollectionBuilder();
					ReportIndexCollection existingProjectContent = builder.Build(this.Project);

					List<string> removeFromProjectFile = new List<string>();

					foreach (string topicId in replace.FlatTopicIds)
					{
						foreach (ReportIndex projectItem in existingProjectContent)
						{
							if (topicId == projectItem.Guid)
							{
								removeFromProjectFile.Add(projectItem.Path);
								break;
							}
						}
					}

					List<string> addToProjectFile = new List<string>();

					addToProjectFile.Add(newContent.Path);
					foreach (Topic topic in newContent.Content)
					{
						addToProjectFile.Add(topic.Path);
					}

					this.Project.RemoveContent(removeFromProjectFile);
					this.Project.AddContent(addToProjectFile);
				}

				replace.ReplaceChildren(newContent);
			}
		}

		public Topic Find(string guid)
		{
			return this.Topics.SearchByGuid(guid);
		}
	}
}
